/*********************************************************************************
 * Copyright (C) [2019] [houzh@msn.com]
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *********************************************************************************/
#ifndef __MENU_BUILDER_H__
#define __MENU_BUILDER_H__
#include <menu/menu.h>
namespace cdroid{
class Context;
class Bundle;
class Parcelable;
class MenuItemImpl;
class MenuPresenter;
class SubMenuBuilder;
class ContextMenuInfo;

class MenuBuilder:virtual public Menu {
private:
    static constexpr const char* PRESENTER_KEY = "android:menu:presenters";
    static constexpr const char* ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
    static constexpr const char* EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
    friend MenuItemImpl;
    friend SubMenuBuilder;
public:
    struct Callback {
        std::function<bool(MenuBuilder&,MenuItem&)> onMenuItemSelected;
        std::function<void(MenuBuilder&)> onMenuModeChange;
    };

    typedef std::function<bool(MenuItemImpl&)>ItemInvoker;
private:
    Context* mContext;

    /**
     * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
     * instead of accessing this directly.
     */
    bool mQwertyMode;

    /**
     * Whether the shortcuts should be visible on menus. Use isShortcutsVisible()
     * instead of accessing this directly.
     */
    bool mShortcutsVisible;

    /**
     * Callback that will receive the various menu-related events generated by
     * this class. Use getCallback to get a reference to the callback.
     */
    Callback mCallback;

    /** Contains all of the items for this menu */
    std::vector<MenuItemImpl*> mItems;

    /** Contains only the items that are currently visible.  This will be created/refreshed from
     * {@link #getVisibleItems()} */
    std::vector<MenuItemImpl*> mVisibleItems;

    /**
     * Contains only the items that should appear in the Action Bar, if present.
     */
    std::vector<MenuItemImpl*> mActionItems;
    /**
     * Contains items that should NOT appear in the Action Bar, if present.
     */
    std::vector<MenuItemImpl*> mNonActionItems;

    /**
     * Default value for how added items should show in the action list.
     */
    int mDefaultShowAsAction;

    /**
     * Current use case is Context Menus: As Views populate the context menu, each one has
     * extra information that should be passed along.  This is the current menu info that
     * should be set on all items added to this menu.
     */
    ContextMenuInfo* mCurrentMenuInfo;

    SparseArray<Parcelable*> mFrozenViewStates;

    bool mIsVisibleItemsStale;
    bool mIsActionItemsStale;
    bool mPreventDispatchingItemsChanged;
    bool mItemsChangedWhileDispatchPrevented;
    bool mOptionalIconsVisible = false;
    bool mIsClosing = false;
    bool mGroupDividerEnabled = false;

    std::vector<MenuItemImpl*> mTempShortcutItemList;
    std::vector<MenuPresenter*> mPresenters;
    MenuItemImpl* mExpandedItem;
private:
    void dispatchPresenterUpdate(bool cleared);
    bool dispatchSubMenuSelected(SubMenuBuilder* subMenu,MenuPresenter* preferredPresenter);
    void dispatchSaveInstanceState(Bundle& outState);
    void dispatchRestoreInstanceState(Bundle& state);
    /**
     * Adds an item to the menu.  The other add methods funnel to this.
     */
    MenuItem* addInternal(int group, int id, int categoryOrder, const std::string& title);

    // Layoutlib overrides this method to return its custom implementation of MenuItemImpl
    MenuItemImpl* createNewMenuItem(int group, int id, int categoryOrder, int ordering,
            const std::string&title, int defaultShowAsAction);
    void removeItemAtInt(int index, bool updateChildrenOnMenuViews);
    static int getOrdering(int categoryOrder);
    void setShortcutsVisibleInner(bool shortcutsVisible);
    static int findInsertIndex(const std::vector<MenuItemImpl*>& items, int ordering);
    void setHeaderInternal(const std::string& titleRes, const std::string& title,const std::string& iconRes, Drawable* icon,View* view);
protected:
    /** Header title for menu types that have a header (context and submenus) */
    std::string mHeaderTitle;
    /** Header icon for menu types that have a header and support icons (context) */
    Drawable* mHeaderIcon;
    /** Header custom view for menu types that have a header and support custom views (context) */
    View* mHeaderView;
protected:
    virtual std::string getActionViewStatesKey();

    void setExclusiveItemChecked(MenuItem& item);
    MenuBuilder& setHeaderTitleInt(const std::string& title);
    MenuBuilder& setHeaderIconInt(Drawable* icon);
    MenuBuilder& setHeaderIconInt(const std::string& iconRes);
    virtual MenuBuilder& setHeaderViewInt(View* view);

    virtual bool isQwertyMode() const;

    virtual bool dispatchMenuItemSelected(MenuBuilder& menu, MenuItem& item);
    void findItemsWithShortcutForKey(std::vector<MenuItemImpl*>& items, int keyCode,const KeyEvent& event);
    MenuItemImpl* findItemWithShortcutForKey(int keyCode,const KeyEvent& event);

    void onItemVisibleChanged(MenuItemImpl& item);
    void onItemActionRequestChanged(MenuItemImpl& item);

public:
    MenuBuilder(Context* context);
    MenuBuilder& setDefaultShowAsAction(int defaultShowAsAction);
    ~MenuBuilder()override;
    void addMenuPresenter(MenuPresenter* presenter);
    void addMenuPresenter(MenuPresenter* presenter, Context* menuContext);
    void removeMenuPresenter(MenuPresenter* presenter);

    void savePresenterStates(Bundle& outState);
    void restorePresenterStates(Bundle& state);

    void saveActionViewStates(Bundle& outStates);
    void restoreActionViewStates(Bundle& states);

    virtual void setCallback(const Callback& cb);

    MenuItem* add(const std::string& title)override;
    MenuItem* add(int group, int id, int categoryOrder, const std::string& title)override;
    SubMenu* addSubMenu(const std::string& title)override;
    SubMenu* addSubMenu(int group, int id, int categoryOrder, const std::string& title)override;

    void setGroupDividerEnabled(bool groupDividerEnabled)override;

    virtual bool isGroupDividerEnabled();

    //int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
    //        Intent[] specifics, Intent intent, int flags, std::vector<MenuItem*>& outSpecificItems);

    void removeItem(int id)override;
    void removeGroup(int group)override;
    void removeItemAt(int index);

    void clearAll();
    void clear()override;

    void setGroupCheckable(int group, bool checkable, bool exclusive)override;
    void setGroupVisible(int group, bool visible);
    void setGroupEnabled(int group, bool enabled)override;

    bool hasVisibleItems()const override;

    MenuItem* findItem(int id)const override;
    int findItemIndex(int id);
    int findGroupIndex(int group);
    int findGroupIndex(int group, int start);

    int size() const override;

    MenuItem* getItem(int index)override;

    bool isShortcutKey(int keyCode,const KeyEvent& event)override;

    void setQwertyMode(bool isQwerty)override;

    virtual void setShortcutsVisible(bool shortcutsVisible);
    virtual bool isShortcutsVisible();

    Context* getContext();

    void changeMenuMode();

    bool performShortcut(int keyCode,KeyEvent& event, int flags)override;

    bool performIdentifierAction(int id, int flags)override;
    bool performItemAction(MenuItem* item, int flags);
    bool performItemAction(MenuItem* item, MenuPresenter* preferredPresenter, int flags);

    void close(bool closeAllMenus);
    void close()override;

    void onItemsChanged(bool structureChanged);
    void stopDispatchingItemsChanged();
    void startDispatchingItemsChanged();
    std::vector<MenuItemImpl*> getVisibleItems();

    void flagActionItems();

    std::vector<MenuItemImpl*> getActionItems();

    std::vector<MenuItemImpl*> getNonActionItems();

    void clearHeader();

    std::string getHeaderTitle();

    Drawable* getHeaderIcon();

    View* getHeaderView();

    virtual MenuBuilder* getRootMenu();

    void setCurrentMenuInfo(ContextMenuInfo* menuInfo);

    void setOptionalIconsVisible(bool visible)override;
    bool getOptionalIconsVisible();

    virtual bool expandItemActionView(MenuItemImpl* item);
    virtual bool collapseItemActionView(MenuItemImpl* item);

    MenuItemImpl* getExpandedItem();
};

}/*endof namespace*/
#endif/*__MENU_BUILDER_H__*/
